import functools

from .ct import Ct
from utils.disk import getCache
from config import CLS_CACHE_PATH

# In order to get decent performance out of LunaDataset, we'll need to invest in
# some on-disk caching. This will allow us to avoid having to read an entire CT
# scan from disk for every sample. Doing so would be prohibitively slow! Make
# sure you're paying attention to bottlenecks in your project and doing what you
# can to optimize them once they start slowing you down. We're kind of jumping
# the gun here since we haven't demonstrated that we need caching here. Without
# caching, the LunaDataset is easily 50 times slower!

raw_cache = getCache(CLS_CACHE_PATH)


# We use a few different caching methods here. First, we're caching the getCt
# return value in memory so that we can repeatedly ask for the same Ct instance
# without having to reload all of the data from disk. That's a huge speed
# increase in the case of repeated requests, but we're only keeping one CT in
# memory, so cache misses will be frequent if we're not careful about access
# order.
@functools.lru_cache(1, typed=True)
def getCt(series_uid):
    return Ct(series_uid)


# After our cache is populated, getCt won't ever be called. These values are
# cached to disk using the Python library diskcache. Tt's much, much faster to
# read in 2**15 float32 values from disk than it is to read in 2**25 int16
# values, convert to float32, and then select a 2**15 subset. From the second
# pass through the data forward, I/O times for input should drop to insignificance.
@raw_cache.memoize(typed=True)
def getCtRawCandidate(series_uid, center_xyz, width_irc):
    ct = getCt(series_uid)
    ct_chunk, center_irc = ct.getRawCandidate(center_xyz, width_irc)
    return ct_chunk, center_irc


@raw_cache.memoize(typed=True)
def getCtSampleSize(series_uid):
    ct = Ct(series_uid, buildMasks_bool=False)
    return len(ct.negative_indexes)
